package com.raymond.utils;

import lombok.Data;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * RestTemplateUtil
 *
 * @author :  raymond
 * @version :  V1.0
 * @date :  2019-10-18 15:47
 */
@Data
@Configuration
@ConfigurationProperties(prefix = "http")
public class RestTemplateUtil {

    /**
     * 从连接池中取连接的超时时间默认30秒
     */
    private int connectionRequestTimeout = 30 * 1000;

    /**
     * 连接超时时间默认20秒
     */
    private int connectTimeout = 20 * 1000;

    /**
     * 响应超时时间默认60秒
     */
    private int socketTimeout = 60 * 1000;

    /**
     * 连接池最大连接数默认20个
     */
    private int maxTotal = 20;

    /**
     * 每个ip最大连接数默认10个
     */
    private int maxPerRoute = 10;
    /**
     * 自动清理时间
     */
    private int clearTime = 15;
    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        RestTemplate restTemplate = builder.build();
        restTemplate.setRequestFactory(clientHttpRequestFactory());
        // 使用 utf-8 编码集的 conver 替换默认的 conver（默认的 string conver 的编码集为"ISO-8859-1"）
        List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
        messageConverters.removeIf(converter -> converter instanceof StringHttpMessageConverter);
        messageConverters.add(new StringHttpMessageConverter(StandardCharsets.UTF_8));

        return restTemplate;
    }

    @Bean
    public HttpClientBuilder httpClientBuilder() {
        HttpClientBuilder builder;
        ConnectionSocketFactory socketFactory = PlainConnectionSocketFactory.getSocketFactory();
        LayeredConnectionSocketFactory sslConnectionSocketFactory = SSLConnectionSocketFactory
                .getSocketFactory();
        Registry<ConnectionSocketFactory> registry = RegistryBuilder
                .<ConnectionSocketFactory> create().register("http", socketFactory)
                .register("https", sslConnectionSocketFactory).build();
        PoolingHttpClientConnectionManager clientConnectionManager = new PoolingHttpClientConnectionManager(
                registry);
        //设置最大连接数
        clientConnectionManager.setMaxTotal(maxTotal);
        //设置每个ip最大连接数
        clientConnectionManager.setDefaultMaxPerRoute(maxPerRoute);
        builder = HttpClients.custom();
        builder.setConnectionManager(clientConnectionManager);
        //25秒没用连接会自动清理
        builder.evictIdleConnections((long) clearTime, TimeUnit.SECONDS);
        return builder;
    }

    @Bean
    public ClientHttpRequestFactory clientHttpRequestFactory() {
        HttpComponentsClientHttpRequestFactory configBuilder = new HttpComponentsClientHttpRequestFactory();
        configBuilder.setHttpClient(httpClientBuilder().build());
        configBuilder.setConnectionRequestTimeout(connectionRequestTimeout);
        // 连接超时，毫秒
        configBuilder.setConnectTimeout(connectTimeout);
        // 读写超时，毫秒
        configBuilder.setReadTimeout(socketTimeout);
        return configBuilder;
    }
}
